package session

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"

	"test.com/common"
	"test.com/fusion"
)

func HandleRegisterAccount(w http.ResponseWriter, r *http.Request) {
	type httpRegisterAccountResp struct {
		common.HTTPRespBase
		AccountID uint32 `json:",omitempty"`
	}
	resp := httpRegisterAccountResp{
		HTTPRespBase: common.HTTPRespBase{Err: int(common.GErrorCodeNone)}}
	defer func() {
		w.Write(fusion.Ingore(json.Marshal(resp))[0].([]byte))
	}()
	account, password := r.FormValue("account"), r.FormValue("password")
	log.Printf("WebClient `%s` HandleRegisterAccount(%s,%s) ...\n",
		r.RemoteAddr, account, password)
	rst, err := common.GlobalDB.Exec(
		"INSERT INTO `t_accounts` VALUES(NULL,?,?,UNIX_TIMESTAMP(),0,0,0,0)",
		account, password)
	if err != nil {
		if strings.HasPrefix(err.Error(), "Duplicate entry") {
			resp.Err = int(common.GErrorCodeAccountDuplicateNameError)
		} else {
			resp.Err = int(common.GErrorCodeInternalError)
		}
		log.Printf("WebClient `%s` HandleRegisterAccount failed, %s.\n",
			r.RemoteAddr, err)
		return
	}
	accountID, err := rst.LastInsertId()
	if err != nil {
		resp.Err = int(common.GErrorCodeInternalError)
		log.Printf("WebClient `%s` HandleRegisterAccount failed, %s.\n",
			r.RemoteAddr, err)
		return
	}
	resp.AccountID = uint32(accountID)
	log.Printf("WebClient `%s` HandleRegisterAccount() is ok.\n",
		r.RemoteAddr)
	return
}

func HandleVerifyAccount(w http.ResponseWriter, r *http.Request) {
	type httpVerifyAccountResp struct {
		common.HTTPRespBase
		AccountID     uint32 `json:",omitempty"`
		LastLogicGsId uint32 `json:",omitempty"`
		Session       string `json:",omitempty"`
		Token         string `json:",omitempty"`
	}
	resp := httpVerifyAccountResp{
		HTTPRespBase: common.HTTPRespBase{Err: int(common.GErrorCodeNone)}}
	defer func() {
		w.Write(fusion.Ingore(json.Marshal(resp))[0].([]byte))
	}()
	account, password := r.FormValue("account"), r.FormValue("password")
	log.Printf("WebClient `%s` HandleVerifyAccount(%s,%s) ...\n",
		r.RemoteAddr, account, password)
	var Id, lastLogicGsId uint32
	var dbPassword string
	var banExpireTime int64
	var allowCheat bool
	err := common.GlobalDB.QueryRow("SELECT `Id`,`password`,`banExpireTime`,"+
		"`lastLogicGsId`,`allowCheat` FROM `t_accounts` WHERE `username`=?", account).
		Scan(&Id, &dbPassword, &banExpireTime, &lastLogicGsId, &allowCheat)
	if err != nil {
		resp.Err = int(common.GErrorCodeInternalError)
		log.Printf("WebClient `%s` HandleVerifyAccount failed, %s.\n",
			r.RemoteAddr, err)
		return
	}
	if !allowCheat || password != "123456" {
		if banExpireTime > time.Now().Unix() {
			resp.Err = int(common.GErrorCodeAccountBanLoginError)
			log.Printf("WebClient `%s` HandleVerifyAccount failed, %s.\n",
				r.RemoteAddr, "account is forbid")
			return
		}
		if password != dbPassword {
			resp.Err = int(common.GErrorCodeAccountValidityError)
			log.Printf("WebClient `%s` HandleVerifyAccount failed, %s.\n",
				r.RemoteAddr, "account password is error")
			return
		}
	}
	token := buildAccountToken()
	err = common.RedisDB.Set(
		fmt.Sprintf("account/token/%d", Id), token, time.Minute*30).Err()
	if err != nil {
		resp.Err = int(common.GErrorCodeInternalError)
		log.Printf("WebClient `%s` HandleVerifyAccount failed, %s.\n",
			r.RemoteAddr, err)
		return
	}
	resp.AccountID, resp.LastLogicGsId = Id, lastLogicGsId
	resp.Session = buildAccountSession(Id)
	resp.Token = token
	log.Printf("WebClient `%s` HandleVerifyAccount() is ok.\n",
		r.RemoteAddr)
	return
}

func HandleGetAccountCharaters(w http.ResponseWriter, r *http.Request) {
	type httpCharacterInfo struct {
		ServerID       uint32
		CharacterID    uint32
		CharacterName  string
		CharacterLevel uint32
	}
	type httpGetAccountCharatersResp struct {
		common.HTTPRespBase
		CharacterInfos []*httpCharacterInfo `json:",omitempty"`
	}
	resp := httpGetAccountCharatersResp{
		HTTPRespBase: common.HTTPRespBase{Err: int(common.GErrorCodeNone)}}
	defer func() {
		w.Write(fusion.Ingore(json.Marshal(resp))[0].([]byte))
	}()
	session, strGsID := r.FormValue("session"), r.FormValue("gsid")
	accountID, err := parseAccountSession(session)
	if err != nil {
		resp.Err = int(common.GErrorCodeParamError)
		return
	}
	gsID, err := strconv.ParseUint(strGsID, 0, 32)
	if err != nil {
		resp.Err = int(common.GErrorCodeParamError)
		return
	}
	log.Printf("WebClient `%s` HandleGetAccountCharaters(%d,%d) ...\n",
		r.RemoteAddr, accountID, gsID)
	var rows *sql.Rows
	strSQL := "SELECT `serverId`,`characterId`,`characterName`,`characterLevel`" +
		" FROM `t_account_characters` WHERE `accountId`=?"
	if gsID == 0 {
		rows, err = common.GlobalDB.Query(strSQL, accountID)
	} else {
		rows, err = common.GlobalDB.Query(strSQL+" AND `serverId`=?", accountID, gsID)
	}
	if err != nil {
		resp.Err = int(common.GErrorCodeInternalError)
		log.Printf("WebClient `%s` HandleGetAccountCharaters failed, %s.\n",
			r.RemoteAddr, err)
		return
	}
	for rows.Next() {
		var info httpCharacterInfo
		err = rows.Scan(&info.ServerID,
			&info.CharacterID, &info.CharacterName, &info.CharacterLevel)
		if err != nil {
			log.Printf("WebClient `%s` HandleGetAccountCharaters failed, %s.\n",
				r.RemoteAddr, err)
		}
		resp.CharacterInfos = append(resp.CharacterInfos, &info)
	}
	log.Printf("WebClient `%s` HandleGetAccountCharaters() is ok.\n",
		r.RemoteAddr)
	return
}

func HandleGetServerList(w http.ResponseWriter, r *http.Request) {
	type httpGetServerListResp struct {
		common.HTTPRespBase
		ServerList []*GameServerInstance `json:",omitempty"`
	}
	resp := httpGetServerListResp{
		HTTPRespBase: common.HTTPRespBase{Err: int(common.GErrorCodeNone)}}
	defer func() {
		w.Write(fusion.Ingore(json.Marshal(resp))[0].([]byte))
	}()
	for _, gsInfo := range InstGameServerMgr.gsInstMap {
		if gsInfo.LogicOpenStatus != common.ServerOpenStatus_Hide {
			resp.ServerList = append(resp.ServerList, gsInfo)
		}
	}
}
